import asyncio
import time
from datetime import datetime

from bleak import BleakClient
from bleak.exc import BleakDeviceNotFoundError

from common import print_service_and_characteristic, disconnected_callback
from utils.math import get_sign_int16

write_uuid = "0000ffe9-0000-1000-8000-00805f9a34fb"
notify_uuid = '0000ffe4-0000-1000-8000-00805f9a34fb'
electric_quantity_bytearray = [0xFF, 0xAA, 0x27, 0x64, 0x00]


async def read_electric_quantity(client: BleakClient):
    """
    读取电量
    特征值uuid
    """
    while client.is_connected:
        await client.write_gatt_char(write_uuid, bytes(electric_quantity_bytearray))
        await asyncio.sleep(5)


async def notify(client: BleakClient):
    """
    姿态通知
    """
    await client.start_notify(notify_uuid, notification_handler)

    try:
        while client.is_connected:
            await asyncio.sleep(1)
    except asyncio.CancelledError:
        pass
    finally:
        await client.stop_notify(notify_uuid)


def notification_handler(sender, data):
    """
    通知数据
    """
    # print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} 收到通知数据 {sender.uuid} {data.hex()}")
    # 解析数据
    if len(data) == 20:
        now = datetime.now()
        date = f"{time.strftime("%Y-%m-%d %H:%M:%S.")}{now.microsecond // 1000:03d}"

        if data[1] == 0x61:
            # 原始数据
            # print(f"{date} {sender.uuid} {data.hex()}")
            RollL, RollH, PitchL, PitchH, YawL, YawH = data[14], data[15], data[16], data[17], data[18], data[19]

            Roll = get_sign_int16(((RollH << 8) | RollL)) / 32768 * 180
            Pitch = get_sign_int16(((PitchH << 8) | PitchL)) / 32768 * 180
            Yaw = get_sign_int16(((YawH << 8) | YawL)) / 32768 * 180

            print(f"{date} X轴: {Roll:.3f}°, Y轴: {Pitch:.3f}°, Z轴: {Yaw:.3f}°")

        elif data[1] == 0x71:
            if data[2] == 0x64:
                qe = get_sign_int16(data[5] << 8 | data[4])
                if qe >= 396:
                    battery_percentage = 100
                elif 393 <= qe < 396:
                    battery_percentage = 90
                elif 387 <= qe < 393:
                    battery_percentage = 75
                elif 382 <= qe < 387:
                    battery_percentage = 60
                elif 379 <= qe < 382:
                    battery_percentage = 50
                elif 377 <= qe < 379:
                    battery_percentage = 40
                elif 373 <= qe < 377:
                    battery_percentage = 30
                elif 370 <= qe < 373:
                    battery_percentage = 20
                elif 368 <= qe < 370:
                    battery_percentage = 15
                elif 350 <= qe < 368:
                    battery_percentage = 10
                elif 340 <= qe < 350:
                    battery_percentage = 5
                else:
                    battery_percentage = 0

                print(f"{date} 剩余电量{battery_percentage}%")

                with open("battery.log", "a", encoding="utf-8") as file:
                    file.write(f"{date} {qe} {battery_percentage}\n")


# 连接到 BLE 设备
async def connect_device(device_address):
    print(f"{time.strftime("%Y-%m-%d %H:%M:%S")} 开始连接 {device_address} ")
    try:
        async with BleakClient(device_address, disconnected_callback) as client:
            print(f"{time.strftime("%Y-%m-%d %H:%M:%S")} 已连接到 {device_address}")

            print_service_and_characteristic(client)

            task1 = asyncio.create_task(read_electric_quantity(client))

            task2 = asyncio.create_task(notify(client))

            try:
                await asyncio.gather(task1, task2)
            except asyncio.CancelledError:
                # 任务被取消时，确保任务已停止
                task1.cancel()
                task2.cancel()
                print("任务已取消")
    except BleakDeviceNotFoundError:
        print(f"{time.strftime("%Y-%m-%d %H:%M:%S")} 设备未找到 {device_address}")


async def main():
    # await connect_device("E8:CC:CB:4D:07:28")
    # await connect_device("DB:94:74:F1:63:07")
    # await connect_device("E1:A4:15:7A:99:BF")
    await connect_device("C6:29:B7:78:69:3A")


# 执行
asyncio.run(main())
